<?php

Raise::load('db.RaiseDbAdapter');

/**
 * SqliteAdapter RaiseDbAdapter class
 * provides gateway to SQLite 2 related functionalities
 *
 * @author Sam-Mauris Yong <hellclanner at live dot com>
 * @license http://www.opensource.org/licenses/bsd-license New BSD License
 * @package Raise.DataAccess.Adapter
 * @since 1.2
 */
class SqliteAdapter extends RaiseDbAdapter {

    /**
     * Stores the last error that occured
     * @var string
     */
    private $lastError = '';

    function __construct() {
        if(!function_exists('sqlite_open')){
            throw new RaiseInvalidRequestException('Unable to load SqliteAdapter because the PHP SQLite extension is not installed or enabled.');
        }
    }

    public function connect() {
        $err = 'Unknown error.';
        $conn = sqlite_open($this->connection()->server(), 0666, &$err);
        if($err){
            throw new RaiseRemoteConnectionException('Unable to connect to SQLite Database source. ' . $err);
        }
        $this->genericConnection($conn);
    }

    public function disconnect() {
        sqlite_close($this->genericConnection());
        $this->genericConnection(null);
        return true;
    }

    public function escapeString($s) {
        return sqlite_escape_string($s);
    }

    public function fetchRowArray() {
        return sqlite_fetch_array($this->result(), SQLITE_NUM);
    }

    public function fetchRowObject($class) {
        return sqlite_fetch_object($this->result(), $class);
    }

    public function lastInsertId() {
        return sqlite_last_insert_rowid($this->genericConnection());
    }

    public function query($q) {
        $err = 'Unknown error.';
        $r = null;
        if(substr_count($q, ';') > 0){
            $r = sqlite_exec($this->genericConnection(), $q, &$err);
        }else{
            $r = sqlite_query($this->genericConnection(), $q, SQLITE_ASSOC, &$err);
        }
        if(!$r){
            if(!$err){
                $this->lastError = sqlite_error_string(sqlite_last_error($this->genericConnection()));;
            }
        }
        $this->result($r);
    }

    public function enquote($name) {
        return '[' . $name . ']';
    }

    public function tableColumns($table) {
        $cmd = new RaiseDbCommand($this->connection(), 'PRAGMA table_info(' . $this->enquote($table) . ');');
        $cs = $cmd->executeFetchArrayTable();
        $columns = new RaiseTypedCollection('RaiseDbTableColumn');
        foreach($cs as $t){
            $c = new RaiseDbTableColumn();
            $c->name($t['name']);
            $c->null($t['notnull'] == 0);
            $c->type($this->translateDataType($t['Type']));
            $c->autoIncrement($c->type == RaiseVariable::TYPEINTEGER && !$c->null());
            $c->primaryKey($t['pk'] == 1);
            $columns->add($c->name(), $c);
        }
        return $columns;
    }

    public function translateDataType($dataType) {
        $dataType = strtolower(trim($dataType));
        if(strpos($dataType, '(') !== false){
            $dataType = substr($dataType, 0, strpos($dataType, '('));
        }
        switch($dataType){
            case 'bit':
            case 'int':
            case 'integer':
            case 'smallint':
            case 'mediumint':
            case 'bigint':
            case 'tinyint':
            case 'serial':
                return RaiseVariable::TYPEINTEGER;
                break;
            case 'bool':
            case 'boolean':
                return RaiseVariable::TYPEBOOLEAN;
                break;
            case 'float':
            case 'double':
            case 'real':
            case 'double precision':
            case 'decimal':
            case 'dec':
                return RaiseVariable::TYPEDOUBLE;
                break;
            case 'char':
            case 'varchar':
            case 'binary':
            case 'varbinary':
            case 'tinyblob':
            case 'blob':
            case 'mediumblob':
            case 'longblob':
            case 'text':
            case 'tinytext':
            case 'mediumtext':
            case 'longtext':
            case 'enum':
            case 'set':
                return RaiseVariable::TYPESTRING;
                break;
            case 'datetime':
            case 'date':
            case 'timestamp':
            case 'time':
            case 'year':
                return 'RaiseDateTime';
                break;
            default:
                return RaiseVariable::TYPEUNKNOWN;
                break;
        }
    }

    public function rowsAffected() {
        return sqlite_changes($this->genericConnection());
    }

    public function transactBegin(){
        throw new RaiseInvalidRequestException('Transaction is not supported for SQLite');
    }

    public function transactCommit(){
        throw new RaiseInvalidRequestException('Transaction is not supported for SQLite');

    }

    public function transactRollback(){
        throw new RaiseInvalidRequestException('Transaction is not supported for SQLite');
    }

    public function lastError(){
        return $this->lastError;
    }

    public function __toString() {
        return 'sqlite';
    }

}
